using Fine.Collections.Intf;
using Fine.TestUtils;
using NUnit.Framework;



namespace Fine.Collections.Const
{
    [TestFixture]
    public class ConstSortSet_test
    {

        #region CONSTRUCTOR AND INITIAL SORTING

        [Test]
        public void Test_ConstructorSort1()
        {
            ConstSortSet<byte> s1 = CC1.SortSetOf<byte>(11);

            Assert.IsTrue(s1.IsNotEmpty);
            Assert.IsFalse(s1.IsEmpty);
            Assert.AreEqual(1, s1.Count);

            Assert.AreEqual(11, s1.First);
            Assert.AreEqual(11, s1.Last);

            Assert.IsTrue(s1.Contains(11));
            Assert.IsTrue(s1.Contains(11));
        }


        [Test]
        public void Test_ConstructorSort2()
        {
            ConstSortSet<byte> s1 = CC1.SortSetOf<byte>(77,33);

            Assert.IsTrue(s1.IsNotEmpty);
            Assert.IsFalse(s1.IsEmpty);
            Assert.AreEqual(2, s1.Count);

            Assert.AreEqual(33, s1.First);
            Assert.AreEqual(77, s1.Last);

            Assert.IsTrue(s1.Contains(33));
            Assert.IsTrue(s1.Contains(77));
        }


        [Test]
        public void Test_ConstructorSort3()
        {
            ConstSortSet<byte> s3 = CC1.SortSetOf<byte>(55, 77, 33);

            Assert.IsTrue(s3.IsNotEmpty);
            Assert.IsFalse(s3.IsEmpty);
            Assert.AreEqual(3, s3.Count);

            Assert.AreEqual(33, s3.First);
            Assert.AreEqual(77, s3.Last);

            Assert.AreEqual(33, s3[1]);
            Assert.AreEqual(55, s3[2]);
            Assert.AreEqual(77, s3[3]);

            Assert.IsTrue(s3.Contains(33));
            Assert.IsTrue(s3.Contains(55));
            Assert.IsTrue(s3.Contains(77));
        }


        [Test]
        public void Test_ConstructorSort5()
        {
            byte[] arr5 = new byte[] { 44, 22, 11, 55, 33 };
            ConstSortSet<byte> s5 = CC1.SortSetOf<byte>(arr5);

            Assert.AreEqual(5, s5.Count);

            Assert.AreEqual(11, s5[1]);
            Assert.AreEqual(22, s5[2]);
            Assert.AreEqual(33, s5[3]);
            Assert.AreEqual(44, s5[4]);
            Assert.AreEqual(55, s5[5]);

            Assert.IsTrue(s5.Contains(11));
            Assert.IsTrue(s5.Contains(22));
            Assert.IsTrue(s5.Contains(33));
            Assert.IsTrue(s5.Contains(44));
            Assert.IsTrue(s5.Contains(55));
        }


        [Test]
        public void Test_Duplicates3()
        {
            var set = CC1.SortSetOf(111L, 333L, 333L, 333L, 333L, 555L);

            set.Contains(111L)._true_();
            set.Contains(333L)._true_();
            set.Contains(555L)._true_();

            long[] array = set.ToArray();

            array._array_(111L, 333L, 555L);

            set.Count._equals_(3);
        }


        [Test]
        public void Test_DuplicatesAtTheBegin()
        {
            var set = CC1.SortSetOf(111L, 111L, 111L, 333L, 555L);

            set.Contains(111L)._true_();
            set.Contains(333L)._true_();
            set.Contains(555L)._true_();

            long[] array = set.ToArray();

            array._array_(111L, 333L, 555L);
        }


        [Test]
        public void Test_DuplicatesAtTheEnd()
        {
            var set = CC1.SortSetOf(111L, 333L, 555L, 555L, 555L);

            set.Contains(111L)._true_();
            set.Contains(333L)._true_();
            set.Contains(555L)._true_();

            long[] array = set.ToArray();

            array._array_(111L, 333L, 555L);
        }


        [Test]
        public void Test_SetWithNullItem()
        {
            var set = CC1.SortSetOf("aaa", (string)null, "bbb");

            set[1]  ._same_(null);
            set[2]  ._equals_("aaa");
            set[3]  ._equals_("bbb");
        }

        #endregion



        #region FIND and INDEX OF

        [TestCase(111L, 1)]
        [TestCase(222L, 2)]
        [TestCase(333L, 3)]
        [TestCase(444L, 4)]
        [TestCase(555L, 5)]
        public void Test_Find_existentItem(long value, int position)
        {
            var set = CC1.SortSetOf(111L,222L,333L,444L,555L);

            bool found;
            int foundPosition;

            set.Find(value, out found, out foundPosition);

            found         ._true_();
            foundPosition ._equals_(position);
        }


        [TestCase(100L, 1)]
        [TestCase(200L, 2)]
        [TestCase(500L, 5)]
        [TestCase(600L, 6)]
        public void Test_Find_nearestItem(long value, int position)
        {
            var set = CC1.SortSetOf(111L,222L,333L,444L,555L);

            bool found;
            int foundPosition;

            set.Find(value, out found, out foundPosition);

            found         ._false_();
            foundPosition ._equals_(position);
        }


        [Test]
        public void Test_Find_emptySet()
        {
            var set = CC1.SortSetOf<long>();

            bool found;
            int position;

            set.Find(1L, out found, out position);
            found     ._false_();
            position  ._equals_(1);
        }


        [Test]
        public void Test_Find_null_no()
        {
            var set = CC1.SortSetOf("aaa","bbb");

            bool found;
            int position;

            set.Find(null, out found, out position);

            found   ._false_();
        }


        [Test]
        public void Test_Find_null_yes()
        {
            var set = CC1.SortSetOf("aaa", (string)null, "bbb");

            bool found;
            int position;

            set.Find((string)null, out found, out position);

            found     ._true_();
            position  ._equals_(1);
        }


        [Test]
        public void Test_IndexOf_positive()
        {
            var set = CC1.SortSetOf("balalaika", "guitar", "zurna");
            int position = set.IndexOf("GuitaR".ToLower());

            position ._equals_(2);
        }


        [Test]
        public void Test_IndexOf_positive_same()
        {
            string guitar = "guitar";

            var set = CC1.SortSetOf("balalaika","guitar","zurna");
            int position = set.IndexOf(guitar);

            position ._equals_(2);
        }


        [Test]
        public void Test_IndexOf_negative()
        {
            var set = CC1.SortSetOf("balalaika","guitar","zurna");
            int position = set.IndexOf("duduk");

            position ._equals_(int.MinValue);
        }


        [Test]
        public void Test_IndexOf_emptySet()
        {
            var set = CC1.SortSetOf<string>();
            int position = set.IndexOf("trumpet");

            position ._equals_(int.MinValue);
        }


        [Test]
        public void Test_IndexOf_null()
        {
            var set = CC0.SortSetOf("balalaika","guitar","zurna");
            int position = set.IndexOf((string)null);

            position ._equals_(int.MinValue);
        }


        [Test]
        public void Test_Contains_null()
        {
            var set = CC.SortSetOf(900, "balalaika", (string)null, "guitar");

            set.IndexOf((string)null)  ._equals_(900);
            set.Contains((string)null) ._true_();
        }

        #endregion



        #region BINARY OPERATIONS

        [Test]
        public void Test_Intersect_1()
        {
            var setA = CC1.SortSetOf("111","222","333");
            var setB = CC1.SortSetOf("222","333","444");

            var setC = setA * setB;

            setC                 ._is_not_null_();
            setC.count           ._equals_(2);
            setC.Contains("111") ._false_();
            setC.Contains("222") ._true_();
            setC.Contains("333") ._true_();
            setC.Contains("444") ._false_();

            setC.FirstIndex._equals_(setA.FirstIndex);
        }


        [Test]
        public void Test_Union_1()
        {
            var setA = CC1.SortSetOf("AAA", "aaa");
            var setB = CC1.SortSetOf("BBB", "bbb");

            var setC = setA + setB;

            setC                  ._is_not_null_();
            setC.count            ._equals_(4);
            setC.Contains("AAA")  ._true_();
            setC.Contains("aaa")  ._true_();
            setC.Contains("BBB")  ._true_();
            setC.Contains("bbb")  ._true_();

            setC.FirstIndex       ._equals_(setA.FirstIndex);
        }


        [Test]
        public void Test_Union_2()
        {
            var setA = CC1.SortSetOf("aaa", "xxx");
            var setB = CC1.SortSetOf("bbb", "xxx");

            var setC = setA + setB;

            setC                  ._is_not_null_();
            setC.count            ._equals_(3);
            setC.Contains("aaa")  ._true_();
            setC.Contains("bbb")  ._true_();
            setC.Contains("xxx")  ._true_();
        }


        [Test]
        public void Test_Minus_1()
        {
            var setA = CC1.SortSetOf("aaa","bbb","ccc");
            var setB = CC1.SortSetOf("bbb","ddd");

            var setC = setA - setB;

            setC.                 _is_not_null_();
            setC.count.           _equals_(2);
            setC.Contains("aaa"). _true_();
            setC.Contains("bbb"). _false_();
            setC.Contains("ccc"). _true_();
            setC.Contains("ddd"). _false_();

            setC.FirstIndex._equals_(setA.FirstIndex);
        }

        #endregion



        #region ITERATOR

        [Test]
        public void Test_Iterator_Basic()
        {
            var set = CC1.SortSetOf(111L, 222L, 333L);

            var it = set.TakeIterator();


            it.Next()   ._true_();
            it.Current  ._equals_(111L);
            it.Next()   ._true_();
            it.Current  ._equals_(222L);
            it.Next()   ._true_();
            it.Current  ._equals_(333L);
            it.Next()   ._false_();
        }


        [Test]
        public void Test_Iterator_Jump()
        {
            var set = CC1.SortSetOf(111L, 222L, 333L, 444L, 555L, 666L, 777L);

            var it = set.TakeIterator();

            it.Next()     ._true_();
            it.Current    ._equals_(111L);

            it.Jump(333L) ._equals_(JumpResult.Exactly);
            it.Current    ._equals_(333L);

            it.Jump(333L) ._equals_(JumpResult.Exactly);
            it.Current    ._equals_(333L);

            it.Jump(500L) ._equals_(JumpResult.Over);
            it.Current    ._equals_(555L);

            it.Jump(100L) ._equals_(JumpResult.Before);
            it.Current    ._equals_(555L);

            it.Jump(800L) ._equals_(JumpResult.End);

            it.Jump(700L) ._equals_(JumpResult.End);
        }


        [Test]
        public void Test_Iterator_Clone()
        {
            var set = CC1.SortSetOf(111L, 222L, 333L, 444L);

            var it1 = set.TakeIterator();

            it1.Next();
            it1.Next();
            it1.Current    ._equals_(222L);

            var it2 = it1.Clone();

            it2.Current    ._equals_(222L);
            it2.Next()     ._true_();
            it2.Next()     ._true_();
            it2.Current    ._equals_(444L);

            it1.Current    ._equals_(222L);
        }


        [Test]
        public void Test_Iterator_Reset()
        {
            var set = CC1.SortSetOf(111L, 222L, 333L);

            var it = set.TakeIterator();

            it.Next();
            it.Next();
            it.Current    ._equals_(222L);

            it.Reset();

            it.Next();
            it.Current    ._equals_(111L);
        }

        #endregion



        #region REMOVE DUPLICATES

        [Test]
        public void Test_RemoveDuplicates_NoDuplicates()
        {
            int[] arr = new int[] {1,2,3,4,5,6,7};
            int count = 7;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr    ._array_(1,2,3,4,5,6,7); // nothing changed
            count  ._equals_(7);
        }

        [Test]
        public void Test_RemoveDuplicates_NoDuplicates_CountLessThanCapacity()
        {
            int[] arr = new int[] {1,2,3,3,3,3,3};
            int count = 3;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr[0] ._equals_(1);
            arr[1] ._equals_(2);
            arr[2] ._equals_(3);
            count  ._equals_(3);
        }

        [Test]
        public void Test_RemoveDuplicates_Duplicates2()
        {
            int[] arr = new int[] {1,2,3,3,4,4,5};
            int count = 7;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr    ._array_(1,2,3,4,5,0,0); 
            count  ._equals_(5);
        }

        [Test]
        public void Test_RemoveDuplicates_Duplicates3()
        {
            int[] arr = new int[] {1,2,3,3,3,4,4,4,5};
            int count = 9;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr    ._array_(1,2,3,4,5,0,0,0,0); 
            count  ._equals_(5);
        }

        [Test]
        public void Test_RemoveDuplicates_DuplicatesAtBegin()
        {
            int[] arr = new int[] {1,1,1,2,3,4,5};
            int count = 7;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr    ._array_(1,2,3,4,5,0,0); 
            count  ._equals_(5);
        }

        [Test]
        public void Test_RemoveDuplicates_DuplicatesAtEnd()
        {
            int[] arr = new int[] {1,2,3,4,5,5,5};
            int count = 7;
            ConstSortSet<int>.RemoveDuplicates(arr, ref count);

            arr    ._array_(1,2,3,4,5,0,0); 
            count  ._equals_(5);
        }

        #endregion

    }
}